package mt.client;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.Timestamp;
import java.util.LinkedList;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

import mt.Order;
import mt.comm.ClientComm;
import mt.comm.ClientCommHandler;
import mt.dummy.ClientMessage;

public class GUI extends JFrame implements MicroTraderClient {


	/**
	 * This class contains three panel that has all the functionality of a client
	 * @author group 55
	 */
	/**
	 * Is constant and sets the size of the window
	 */
	private final Dimension FRAME_SIZE = new Dimension(500, 500);
	/**
	 *  responsible for all the functions related to connection
	 */
	private TopPanel topPanel;
	/**
	 * responsible for all the functions related to order
	 */
	private MiddlePanel middlePanel;
	/**
	 *  responsible to provide the customer with the last order 
	 * received by the server. 
	 */
	private EndPanel endPanel;
	/**
	 * Nickname of the client
	 */
	private String nickname;
	/**
	 * responsible for communication between client server
	 */
	//private ClientCommHandler ccd;
	private ClientCommHandler ccd;
	/**
	 * responsible for keeping all the information you the order sent by the server
	 */
	private LinkedList<Order> orders = new LinkedList<Order>();
	/**
	 * Name of the host
	 */
	private String host = "localhost";

	private LinkedList<HistNod> History = new LinkedList<HistNod>();
	/**
	 * Nickname of the client
	 * @param nickname     Nickname of the client
	 * @param topPanel     responsible for all the functions related to connection
	 * @param middlePannel responsible for all the functions related to order
	 * @param endPanel     responsible to provide the customer with the last order 
	 *                 received by the server. 
	 */
	public GUI() {

		setNickname(new JOptionPane().showInputDialog("Insira o seu nickname"));
		//ccd = new ClientCommHandler();
		ccd = new ClientCommHandler();
		topPanel = new TopPanel(nickname);
		middlePanel = new MiddlePanel();
		endPanel = new EndPanel();
	}

	/**
	 * Procedure responsible for the initiation of the customer, 
	 * ie start graphics and connection to the server
	 */

	public void init() {
		build();
		connectionListener();
		movimentListener(); 
		ordersListener();
		setVisible(true);
	}

	/**
	 * procedure responsible for the layout configuration 
	 */

	private void build() {
		setTitle("MicroTrader");
		setSize(FRAME_SIZE);
		setResizable(false);
		setLocationRelativeTo(null);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setLayout(new GridBagLayout());

		GridBagConstraints gbc = new GridBagConstraints();
		gbc.fill = GridBagConstraints.BOTH;
		gbc.weightx = 1;

		// topPanel
		gbc.weighty = 0.1;
		gbc.gridy = 0;
		add(topPanel, gbc);

		// middlePanel
		gbc.weighty = 0.9;
		gbc.gridy = 1;
		add(middlePanel, gbc);
		//setTradeButtonsOff();

		// endPanel
		gbc.gridy = 2;
		add(endPanel, gbc);
	}

	public void setNickname(String nickname) {
		this.nickname = nickname;
	}

	/**
	 * Procedure responsible for carry out a connection to the server  
	 */
	@Override
	public void start(ClientComm clientComm) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				getComm().connect("localhost", nickname);
				setTradeButtonsOn();
				while (getComm().isConnected()) {
					if (getComm().hasNextMessage()) {
						ClientMessage message = getComm().getNextMessage();
						Order order = message.getOrder();
						System.out.println(order);
						if (message.getType().equals(mt.comm.ClientSideMessage.Type.ORDER)) {
							if (!existOrder(order)) {
								if(order.getNumberOfUnits()>0)//se for algo com unidades 0 n vale a pena fazer add
									orders.add(order);
							} else {
								updateOrder(order);
							}
						} else {
							// show error
							System.out.println("ERROR: " + message.getError());
						}
					}

					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
	}

	private void setTradeButtonsOn() {
		middlePanel.getBuy().setEnabled(true);
		middlePanel.getSell().setEnabled(true);
		middlePanel.getHistory().setEnabled(true);
	}

	private void setTradeButtonsOff() {
		middlePanel.getBuy().setEnabled(false);
		middlePanel.getSell().setEnabled(false);
		middlePanel.getHistory().setEnabled(true);
	}

	/**
	 * responsible for saying whether a particular order exists in linkedlist Orders
	 *
	 * @param order
	 * @return true if the order exist in the linkedList Ordes else return false. 
	 */
	private boolean existOrder(Order order) {
		for (Order o : orders) {
			if (o.getServerOrderID() == order.getServerOrderID()) 
				return true;
		}
		return false;
	}

	/**
	 * Procedure responsible for updating an order
	 * @param order 
	 */

	private void updateOrder(Order order) {

		for (Order o : orders) {
			if (o.getServerOrderID() == order.getServerOrderID()) {
				if(order.getNumberOfUnits()==0){
					orders.remove(o);
					break;
				} else {
					orders.remove(o);
					orders.add(order);
					break;

				}
			}
		} 
	}

	/**
	 * Procedures responsible for the interaction of buttons related to a connection server
	 */
	private void connectionListener(){
		topPanel.getConnectButton().addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				connect();
			}
		});

		topPanel.getDisconnectButton().addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				disconnect();
			}
		});
	}

	public void connect() {
		topPanel.getConnectButton().setEnabled(false);
		start(ccd);
		topPanel.getDisconnectButton().setEnabled(true);
	}

	public void disconnect() {
		topPanel.getConnectButton().setEnabled(true);
		getComm().disconnect();
		topPanel.getDisconnectButton().setEnabled(false);
		setTradeButtonsOff();
		orders.clear();
	}

	public LinkedList<Order> getOrders() {
		return orders;
	}

	/**
	 * Procedures responsible for the interaction of buttons related to buy and sell orders
	 */
	private void ordersListener() {
		middlePanel.getBuy().addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				java.util.Date date= new java.util.Date();

				Order o = null;
				String stock = new JOptionPane().showInputDialog("Insert the name of the Stock");
				String num = new JOptionPane().showInputDialog("Insert the number of units you whant to buy");
				int numberOfUnits = Integer.parseInt(num);
				String preco = new JOptionPane().showInputDialog("Insert the price of each units you whant to buy");
				double pricePerUnit = Double.parseDouble(preco);
				o = Order.createBuyOrder(nickname, stock, numberOfUnits, pricePerUnit);
				HistNod node= new HistNod(o, new Timestamp(date.getTime()));
				History.add(node);
				getComm().sendOrder(o);
			}
		});

		middlePanel.getSell().addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				java.util.Date date= new java.util.Date();
				Order o = null;
				String stock = new JOptionPane().showInputDialog("Insert the name of the Stock");
				String numUnits = new JOptionPane().showInputDialog("Insert the number of units you whant to sell");
				String price = new JOptionPane().showInputDialog("Insert the price of each units you whant to sell");
				int numberOfUnits = Integer.parseInt(numUnits);
				double pricePerUnit= Double.parseDouble(price);
				o = Order.createSellOrder(nickname, stock, numberOfUnits, pricePerUnit);
				HistNod node= new HistNod(o, new Timestamp(date.getTime()));
				History.add(node);
				getComm().sendOrder(o);
			}
		});
	}

	/**
	 * Procedures responsible for the interaction of button to view available orders
	 */
	private void movimentListener() {
		middlePanel.getHistory().addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				ViewHistoryWindow window = new ViewHistoryWindow(History);
			}
		});
		middlePanel.getViewOrders().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				ViewOrderWindow window = new ViewOrderWindow(orders);
			}
		});
	}

	/**
	 * returns the clientDummy connection
	 */	
	/*public ClientCommHandler getComm() {
		return ccd;
	}*/

	public ClientCommHandler getComm() {
		return ccd;
	}
	
	/**
	 * returns the client nickname
	 */
	public String getNickname() {
		// TODO Auto-generated method stub
		return nickname;
	}

}
